<?php

namespace Controller;

use Lib\src\Validator;
use vendor\DatabaseConnection;
use Lib\BaseController;

/**
 * Created by PhpStorm.
 * User: Se1per
 * Date: 2023/5/25
 * Time: 22:06
 */
class UserController extends BaseController
{
    private $database;

    public function __construct()
    {
        $this->database = DatabaseConnection::getInstance()->getConnection();
    }

    /**
     * 创建用户账号
     * @return array
     * @throws \Exception
     */
    public function saveUserData(): array
    {
        $data = $this->get_all_params();

        //TODO 验证器 可以后续添加到 继承控制器中 或者全局引入 验证层 进行二次封装 (简单实现)
        $validator = new Validator($data,
            [
                'user_account' => 'required|minlength:4|maxlength:18',
                'user_name' => 'minlength:4|maxlength:18',
                'email' => 'email',
                'phone' => 'mobile',
                'password' => 'required|minlength:6|maxlength:32',
            ],
            [
                'user_account.required' => '用户账号不能为空',
                'user_account.minlength' => '用户账号长度不能小于4',
                'user_account.maxlength' => '用户账号长度不能大于18',

                'user_name.minlength' => '用户名称长度不能小于4',
                'user_name.maxlength' => '用户名称长度不能大于18',

                'email.email' => '邮箱格式不正确',
                'phone.mobile' => '手机格式不正确',

                'password.required' => '密码不能为空',
                'password.minlength' => '密码长度不能小于6',
                'password.maxlength' => '密码长度不能大于32',
            ]
        );

        list($validator, $msg) = $validator->validate();

        if (!$validator) return $this->JsonMain(200001, '请求失败验证参数:', $msg);

        //TODO 重复检查需要移到验证器处理,时间有限简单写控制器实现
        //检查手机号码 重复
        $checkPhone = "select count(*) from test_user where deleted_at IS NULL AND status = 1 AND phone = " . $data['phone'];
        $result = mysqli_query($this->database, $checkPhone);
        $checkPhone = false;
        while ($row = mysqli_fetch_assoc($result)) {
            $checkPhone = $row;
        }
        if (array_shift($checkPhone)) return $this->JsonMain(200002, '请求失败:已经存在相同手机号码,请重新输入您得手机号码');

        //检查用户名 重复
        $checkPhone = "select count(*) from test_user where deleted_at IS NULL AND status = 1 AND user_account = " . '"' . $data['user_account'] . '"';
        $result1 = mysqli_query($this->database, $checkPhone);
        $checkPhone = false;
        while ($row = mysqli_fetch_assoc($result1)) {
            $checkPhone = $row;
        }
        if (array_shift($checkPhone)) return $this->JsonMain(200002, '请求失败:已经存在相同用户名,请重新输入您得用户名');

        //操作入库
        $sql = "INSERT INTO test_user (user_account, user_name, email, password,salt, phone,created_at,updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";

        $stmt = $this->database->prepare($sql);
        $salt = uniqid();

        $arr = [
            $data['user_account'],
            $data['user_name'],
            $data['email'],
            $this->makePassWord($data['password'], $salt),
            $salt,
            $data['phone'],
            date('Y-m-d H:i:s'),
            date('Y-m-d H:i:s'),
        ];

        try {

            $stmt->bind_param("ssssssss", ...$arr);

            if ($stmt->execute()) {
                return $this->JsonMain(200000, '请求成功:账户创建成功');
            }

        } catch (\Exception $e) {

            return $this->JsonMain(200000, '请求失败:账户创建失败');

        }

        return $this->JsonMain(200000, '请求失败:账户创建失败');

    }

    /**
     * 短信发送接口
     * @return array
     * @throws \Exception
     */
    public function sendSMS(): array
    {
        //TODO 设计思路 lib 创建 公有入口文件以接口得方式多态调用不同得短信接口,所有逻辑代码都是
        //TODO 例: $sendResult = SmsClass::SendSMS(); 这里得SendSMS 方法在共同得类中,是根据配置文件得指定和非指定获取配置和发送平台,或数据库,记录得短信剩余数量
        //TODO 以接口必须实现方法得逻辑实例化后构造函数即判断 发送那个短信平台,依赖配置文件写好得 ali=>[key=>xxx,....] 以键值为判断实例化调用不同平台发送
        $data = $this->get_all_params();

        //TODO 验证器 可以后续添加到 继承控制器中 或者全局引入 验证层 进行二次封装 (简单实现)
        $validator = new Validator($data,
            [
                'phone' => 'required|mobile',
            ],
            [
                'phone.required' => '手机号码必须填写',
                'phone.mobile' => '手机格式不正确',
            ]
        );

        list($validator, $msg) = $validator->validate();

        if (!$validator) return $this->JsonMain(200001, '请求失败验证参数:', $msg);

        //检查手机号码 是否存在
        $checkPhone = "select count(*) from test_user where deleted_at IS NULL AND status = 1 AND phone = " . $data['phone'];
        $result = mysqli_query($this->database, $checkPhone);
        $checkPhone = false;
        while ($row = mysqli_fetch_assoc($result)) {
            $checkPhone = $row;
        }
        if (!array_shift($checkPhone)) return $this->JsonMain(200002, '请求失败:该手机号码不存在,无法使用该手机号码登录');

        //TODO 还需要添加短信发送上限,由于要求里面没写,所以这里简单备注,每天或者 5分钟内不能超过发送多少次
        $sms = $this->getARandLetter(6, null, 'ab');

        $sql = "INSERT INTO test_sms (code,phone,created_at,updated_at) VALUES (?, ?,?, ?)";

        $stmt = $this->database->prepare($sql);

        $arr = [
            $sms,
            $data['phone'],
            date('Y-m-d H:i:s'),
            date('Y-m-d H:i:s'),
        ];

        try {

            $stmt->bind_param("ssss", ...$arr);

            if ($stmt->execute()) {
                return $this->JsonMain(200000, '请求成功:短信已发送成功');
            }

        } catch (\Exception $e) {

            return $this->JsonMain(200000, '请求失败:短信发送失败');

        }

        return $this->JsonMain(200000, '请求失败:短信发送失败');
    }

    /**
     * 登录逻辑
     * @return array
     * @throws \Exception
     */
    public function userLogin(): array
    {
        $data = $this->get_all_params();

        //TODO 验证器 可以后续添加到 继承控制器中 或者全局引入 验证层 进行二次封装 (简单实现)
        $validator = new Validator($data,
            [
                'user_account' => 'minlength:4|maxlength:18',
                'code' => 'minlength:6|maxlength:6',
                
                'email' => 'email',
                'phone' => 'mobile',
                
                'password' => 'minlength:6|maxlength:32',
            ],
            [
                'user_account.minlength' => '用户账号长度不能小于4',
                'user_account.maxlength' => '用户账号长度不能大于18',

                'code.minlength' => '验证码长度不能小于6',
                'code.maxlength' => '验证码长度不能大于6',

                'email.email' => '邮箱格式不正确',
                'phone.mobile' => '手机格式不正确',

                'password.required' => '密码不能为空',
                'password.minlength' => '密码长度不能小于6',
                'password.maxlength' => '密码长度不能大于32',
            ]
        );

        list($validator, $msg) = $validator->validate();

        if (!$validator) return $this->JsonMain(200001, '请求失败验证参数:', $msg);

        //TODO 登录逻辑大部分需要封装,例如 $this->Repository->userLogin(); 封装到 Repository 层中 利用多态特性和传输参数调用不同得登录逻辑,时间不够,所以简单把逻辑写到控制器中

        if(isset($data['user_account'])){
            // 账号登录逻辑
            //检查手机号码 重复
            $checkAccess = "select id,user_name,email,password,salt from test_user where deleted_at IS NULL AND status = 1 AND user_account = " . '"' . $data['user_account'] . '"';

            $result = mysqli_query($this->database, $checkAccess);
            $checkPhone = false;
            while ($row = mysqli_fetch_assoc($result)) {
                $checkPhone = $row;
            }
            if (!isset($checkPhone['password'])) return $this->JsonMain(200002, '登录失败:无法找到该用户,请重新输入');

            if($this->makePassWord($data['password'],$checkPhone['salt']) != $checkPhone['password']){
                return $this->JsonMain(200002, '登录失败:密码不正确,请重新输入');
            }
            
        }else if(isset($data['phone']) && isset($data['code'])){
            //校验验证码
            $checkCode = 'select count(*) from test_sms where status = 1 AND code = ' .'"'. $data['code'] .'"'. " AND phone = " .'"'.$data['phone'].'"';
            $result = mysqli_query($this->database, $checkCode);
            $checkPhone = false;
            while ($row = mysqli_fetch_assoc($result)) {
                $checkPhone = $row;
            }
            if (!array_shift($checkPhone)) return $this->JsonMain(200002, '请求失败:该验证码不正确,请重新输入');

            // 手机号码 短信登录逻辑
            $checkAccess = "select id,user_name,email,password,salt from test_user where deleted_at IS NULL AND status = 1 AND phone = " . $data['phone'];
            $result = mysqli_query($this->database, $checkAccess);
            $checkPhone = false;
            while ($row = mysqli_fetch_assoc($result)) {
                $checkPhone = $row;
            }
            if (!isset($checkPhone['password'])) return $this->JsonMain(200002, '登录失败:无法找到该用户,请重新输入');


        }else if(isset($data['email'])){
            // 账号登录逻辑
            $checkAccess = "select id,user_name,email,password,salt from test_user where deleted_at IS NULL AND status = 1 AND email = " . '"' . $data['email'] . '"';

            $result = mysqli_query($this->database, $checkAccess);
            $checkPhone = false;
            while ($row = mysqli_fetch_assoc($result)) {
                $checkPhone = $row;
            }

            if (!isset($checkPhone['password'])) return $this->JsonMain(200002, '登录失败:无法找到该用户,请重新输入');

            if($this->makePassWord($data['password'],$checkPhone['salt']) != $checkPhone['password']){
                return $this->JsonMain(200002, '登录失败:密码不正确,请重新输入');
            }
        }else{
            return $this->JsonMain(200002, '登录失败:密码不正确,请重新输入');
        }
        //记录session
        session_status();
        $_SESSION['user'] = $checkPhone['user_name'];
        return $this->JsonMain(200000, '请求成功:登录成功');

    }

}